﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using CompactMapper.Orm.Contracts;
using CompactMapper.Orm.Enumerations;

namespace CompactMapper.Orm.Queries
{
    public abstract class Query
    {
        protected readonly List<Criterion> _criteria;

        protected Query()
        {
            _criteria = new List<Criterion>();
        }

        public IEnumerable<Criterion> Criteria
        {
            get { return _criteria; }
        }

        public static readonly Query Null = new NullQuery();
        private class NullQuery : Query
        {
        }
    }

    public class Query<T> : Query
    {
        public new IEnumerable<Criterion<T>> Criteria
        {
            get { return _criteria.OfType<Criterion<T>>(); }
        }

        public Query<T> StringEquals(Expression<Func<T, String>> columnExpression, String targetValue)
        {
            _criteria.Add(new StringEqualsCriterion<T>(columnExpression, targetValue));
            return this;
        }

        public Query<T> StringLike(Expression<Func<T, String>> columnExpression, String targetValue)
        {
            _criteria.Add(new StringLikeCriterion<T>(columnExpression, targetValue));
            return this;
        }

        public Query<T> PrimaryKey(IKey primaryKey)
        {
            _criteria.Add(new PrimaryKeyCriterion<T>(primaryKey));
            return this;
        }

        public Query<T> EnumEquals<TEnumVal, TBackingVal>(Expression<Func<T, TEnumVal>> columnExpression,
                                                          TBackingVal targetValue)
            where TEnumVal : Enumeration<TBackingVal>
        {
            _criteria.Add(new EnumEqualsCriterion<T, TEnumVal, TBackingVal>(columnExpression, targetValue));
            return this;
        }

        public Query<T> IntegerEquals(Expression<Func<T, int>> columnExpression, int targetValue)
        {
            _criteria.Add(new IntegerEqualsCriterion<T>(columnExpression, targetValue));
            return this;
        }

        public Query<T> LongEquals(Expression<Func<T, long>> columnExpression, long targetValue)
        {
            _criteria.Add(new LongEqualsCriterion<T>(columnExpression, targetValue));
            return this;
        }


    }
}